package com.apobates.jforum2.troll.utils.core;

import com.apobates.jforum2.troll.utils.core.api.OptionalEntityTransformMapper;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * REST Api响应结果
 * @author xiaofanku
 * @param <T>
 */
public class ResponseResult<T extends Object> {
    private final int code;
    private final String message;
    private final T data;
    private final static Logger logger = LoggerFactory.getLogger(ResponseResult.class);

    private ResponseResult(int code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public T getData() {
        return data;
    }
    
    public T getEntity(){
        return getData();
    }

    /**
     * 对于操作类的执行逻辑包装.避免大量的try/catch
     * @param resultFun 返回Optional<Boolean>结果的表达式
     * @param failMessage 表达式失败时的消息内容, 以表达式的结果为判断依据
     * @return
     */
    public static ResponseResult<String> ofBoolean(Supplier<Optional<Boolean>> resultFun, String failMessage){
        String message="OK";boolean affect=false;
        try{
            affect = resultFun.get().orElse(false);
            if(!affect){
                message=failMessage;
            }
        }catch(Exception e){
            message=e.getMessage();
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }else{
                logger.error("[RR][S]ofBoolean exception:" +e.getMessage());
            }
        }
        return Helper.ofBoolean(affect, message);
    }
    /**
     * 对于操作类的执行逻辑包装.避免大量的try/catch
     * @param resultFun 返回Integer结果的表达式
     * @param failMessage 表达式失败时的消息内容, 以结果的正值性(>0)为判断依据
     * @return
     */
    public static ResponseResult<String> ofIntegerResult(Supplier<Integer> resultFun, String failMessage){
        String message="OK";int affect=0;
        try{
            affect = resultFun.get();
            if(affect<=0){
                message = failMessage;
            }
        }catch(Exception e){
            message=e.getMessage();
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }else{
                logger.error("[RR][S]ofIntegerResult exception:" +e.getMessage());
            }
        }
        return Helper.ofInteger(affect, message);
    }
    /**
     * 对于操作类的执行逻辑包装.避免大量的try/catch
     * @param resultFun 返回Optional<Long>结果的表达式
     * @param failMessage 表达式失败时的消息内容, 以结果的有效性(>0)为判断依据
     * @return
     */
    public static ResponseResult<String> ofLongResult(Supplier<Optional<Long>> resultFun, String failMessage){
        String message="OK";long record=0L;
        try{
            Optional<Long> opt = resultFun.get();
            if(!opt.isPresent()){
                message = failMessage;
            }else{
                record = opt.get();
                if(record<=0){
                    message = failMessage;
                }
            }
        }catch(Exception e){
            message=e.getMessage();
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }else{
                logger.error("[RR][S]ofLongResult exception:" +e.getMessage());
            }
        }
        return Helper.ofLong(record, message);
    }

    /**
     * 对于操作类的执行逻辑包装.避免大量的try/catch
     * @param resultFun 返回Optional<T>结果的表达式
     * @param mapper T到U的映射函数
     * @param <T> 执行结果的类型
     * @param <U> 最终的输出类型/映射函数转换后的类型
     * @return
     */
    public static <T,U> ResponseResult<U> ofEntityVo(Supplier<Optional<T>> resultFun, OptionalEntityTransformMapper<T,U> mapper){
        Optional<T> ins = Optional.empty();
        try {
            ins = resultFun.get();
        }catch (Exception e){
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }else{
                logger.error("[RR][S]ofEntityVo exception:" +e.getMessage());
            }
        }
        ResponseResult<U> rr = ResponseResult.Helper.ofOptional(mapper.transform(ins));
        return rr;
    }

    public static ResponseResult<String> ofString(String value, String errMessage){
        int code;
        String message;
        String ins=null;
        if(Commons.isNotBlank(value)){
            code = 200;
            message = "OK";
            ins = value;
        }else{
            code = 417;
            message = errMessage;
        }
        return new ResponseResult<>(code, message, ins);
    }

    /**
     * 生成404的响应结果
     * @return
     */
    public static ResponseResult<String> notFound(){
        return new ResponseResult<>(404, "查找的对象不存在", "");
    }
    
    /**
     * 分页类响应结果
     * @param pageResult
     * @param <T>
     * @return
     */
    public static <T extends Object> ResponseResult<EntityPageResult<T>> of(EntityPageResult<T> pageResult){
        return new ResponseResult<>(200, "OK", pageResult);
    }

    /**
     * 对于Spring ResponseEntity的载体进行转换
     * ResponseEntity,ResponseEntity<Object>接受端在body中获取不到值总是null.
     * 调用此方法的ResponseEntity需要设置ContentType=MediaType.APPLICATION_JSON
     *
     * @return
     */
    public String toJson(){
        return new Gson().toJson(getEntity());
    }

    /**
     * 助手类
     */
    public static class Helper{
        /**
         * 参数对象(result)大于0表示成功(200),成功的提示消息为:OK
         * @param result 响应结果
         * @param errMessage 错误消息
         * @return
         */
        public static ResponseResult<String> ofInteger(int result, String errMessage){
            int code = (result>0)?200:500;
            String _msg = (code==200)?"OK":errMessage;
            return new ResponseResult<>(code, _msg, result+"");
        }

        /**
         * 参数对象(result)大于0表示成功(200),成功的提示消息为:OK
         * @param result 响应结果
         * @param errMessage 错误消息
         * @return
         */
        public static ResponseResult<String> ofLong(long result, String errMessage){
            int code = (result>0)?200:500;
            String _msg = (code==200)?"OK":errMessage;
            return new ResponseResult<>(code, _msg, result+"");
        }

        /**
         * 参数对象isPresent等于true表示成功(200),成功的提示消息为:OK,反之表示失败(404),提示消息为:查找的对象不存在
         * @param <T>
         * @param result 响应结果
         * @return
         */
        public static <T extends Object> ResponseResult<T> ofOptional(Optional<T> result){
            int code = 200;
            String message = "OK";
            if(!result.isPresent()){
                code = 404;
                message = "查找的对象不存在";
            }
            return new ResponseResult<>(code, message, result.orElse(null));
        }

        /**
         * 参数对象不等于null表示成功(200),成功的提示消息为:OK,反之表示失败(404),提示消息为:查找的对象不存在
         * @param <T>
         * @param result 响应结果
         * @return
         */
        public static <T extends Object> ResponseResult<T> ofEntity(T result){
            int code = (null == result)?404:200;
            String message = (null == result)?"查找的对象不存在":"OK";
            return new ResponseResult<>(code, message, result);
        }

        /**
         * 参数对象等于true表示成功(200),成功的提示消息为:OK,反之表示失败(500),提示消息为:操作失败
         * @param result 响应结果
         * @return
         */
        public static ResponseResult<String> ofBoolean(boolean result){
            String message = (result)?"OK":"操作失败";
            return ofBoolean(result, message);
        }

        /**
         * 参数对象(result)等于true表示成功(200),成功的提示消息为:OK,反之表示失败(500),提示消息为:错误消息
         * @param result 响应结果
         * @param errMessage 错误消息
         * @return
         */
        public static ResponseResult<String> ofBoolean(boolean result, String errMessage){
            String _msg = (result)?"OK":errMessage;
            return new ResponseResult<>(result?200:500, _msg, result?"1":"0");
        }
    }

    /**
     * 分页结果的助手类
     * @param <R>
     * @param <T>
     */
    public static class PageResultBuilder<R extends Object, T extends Object>{
        private final int page;
        private final int pageSize;
        private long total = 0L;
        private Stream<T> result;

        private PageResultBuilder(int page, int pageSize){
            this.page = page;
            this.pageSize = pageSize;
        }

        public static <R extends Object, T extends Object> PageResultBuilder<R,T> getInstance(int page, int pageSize){
            return new PageResultBuilder<>(page, pageSize);
        }

        public PageResultBuilder<R,T> from(long total, Stream<T> result){
            this.total = total;
            this.result = result;
            return this;
        }

        public ResponseResult<EntityPageResult<R>> build(final Function<T,R> mapper){
            EntityPageResult<R> ins =  new EntityPageResult<>();
            ins.setPage(getPage());
            ins.setSize(getPageSize());
            ins.setTotal(getTotal());
            ins.setResult(getResult().map((T obj)->mapper.apply(obj)).collect(Collectors.toList()));
            return ResponseResult.of(ins);
        }

        public <U> ResponseResult<EntityPageResult<R>> build(final BiFunction<T,U,R> mapper, final U param){
            EntityPageResult<R> ins =  new EntityPageResult<>();
            ins.setPage(getPage());
            ins.setSize(getPageSize());
            ins.setTotal(getTotal());
            ins.setResult(getResult().map((T obj)->mapper.apply(obj, param)).collect(Collectors.toList()));
            return ResponseResult.of(ins);
        }

        public int getPage() {
            return page;
        }

        public int getPageSize() {
            return pageSize;
        }

        public long getTotal() {
            return total;
        }

        public Stream<T> getResult() {
            return result;
        }
    }
}